package main

import "fmt"

////// 选项模式

//从这里可以看到，为了实现选项的功能，我们增加了很多的代码，实现成本相对还是较高的，所以实践中需要根据自己的业务场景去权衡是否需要使用。个人总结满足下面条件可以考虑使用选项模式
//
// - 参数确实比较复杂，影响调用方使用
// - 参数确实有比较清晰明确的默认值
// - 为参数的后续拓展考虑

// old
//func MyFunc1(requiredStr string, str1 string, str2 string, int1 int, int2 int) {
//	fmt.Println(requiredStr, str1, str2, int1, int2)
//}
//// 调用方法
//MyFunc1("requiredStr", "defaultStr1", "defaultStr2", 1, 2)

type MyFuncOptions struct {
	optionStr1 string
	optionStr2 string
	optionInt1 int
	optionInt2 int
}

var defaultMyFuncOptions = MyFuncOptions{
	optionStr1: "defaultStr1",
	optionStr2: "defaultStr2",
	optionInt1: 1,
	optionInt2: 2,
}

type MyFuncOption func(options *MyFuncOptions)

// With
func WithOptionStr1(str1 string) MyFuncOption {
	return func(options *MyFuncOptions) {
		options.optionStr1 = str1
	}
}

func WithOptionInt1(int1 int) MyFuncOption {
	return func(options *MyFuncOptions) {
		options.optionInt1 = int1
	}
}

func WithOptionStr2AndInt2(str2 string, int2 int) MyFuncOption {
	return func(options *MyFuncOptions) {
		options.optionInt2 = int2
		options.optionStr2 = str2
	}
}

// 假设第一个为必填参数
//使用 With 方法返回的选项方法作为参数列表，用这些方法去设置选项
func MyFunc2(requiredStr string, opts ...MyFuncOption) {
	options := defaultMyFuncOptions
	for _, o := range opts {
		o(&options)
	}
	fmt.Println(requiredStr, options.optionStr1, options.optionStr2, options.optionInt1, options.optionInt2)
}

func main() {
	MyFunc2("必填参数", WithOptionStr1("可选参数1"))
	MyFunc2("必填参数", WithOptionStr2AndInt2("可选参数1", 9999))
}
